package pokeronlab_2014.mcts;
import java.util.LinkedList;
import java.io.PrintStream;
import java.lang.*;
import java.util.List;
//import java.util.ResourceBundle.Control;
//
//import com.biotools.meerkat.Card;









import java.util.prefs.InvalidPreferencesFormatException;

import com.biotools.meerkat.Deck;
import com.biotools.meerkat.Card;
import com.biotools.meerkat.Hand;
import com.biotools.meerkat.HandEvaluator ;

import pokeronlab_2014.ConfigManager;
import pokeronlab_2014.Controller;
import pokeronlab_2014.Database;
import pokeronlab_2014.mcts.TreeNode.NodeType;


public class MCTSDecision{ 
	/**
	 * döntéshozásnál hányszor menjünk le showdone-ig a kiválasztott csúcsból
	 */
	int szimulacio =1;
	
	double hatvany;
	
	/**
	 * Az MCTS algoritmus hányszor fusson le egymás után
	 */
	int MCTS;


	
	enum Action{
		call_check,
		fold,
		raise
	};
	
	Action action;
	
	Database DataBase = new Database();
	
	List<TreeNode> visited = new LinkedList<TreeNode>();
	
	
	public TreeNode currentNode;
	TreeNode selectionNode;
	TreeNode simulationNode;	
    public TreeNode root;
    int myID;
    
    //ElapsedTimer t = new ElapsedTimer();
    
    /*TreeView tv = new TreeView(tn);
    tv.showTree("After " + n + " play outs");
    System.out.println("Done");*/
    // Ha meg akarjuk nézni a fát ezt a fenti kódot kell megírni
	
	
//	int getDecision(){
//		return 4;
//	}
	
    public MCTSDecision(){
    	try {
			//lekérjük a MCTS értékét
			MCTS = Integer.parseInt(ConfigManager.getMCTS().getValue("MCTS"));
		} catch (InvalidPreferencesFormatException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
    	
    }
    
	
	/**
	 * A floppon mikor mi jövünk először beállítjuk a gyükércsúcsot
	 * @throws InvalidPreferencesFormatException 
	 */
	public void setTreeRoot() throws InvalidPreferencesFormatException{
		root = Database.getInstance().getTreeRoot();
		currentNode = root;
		int c;
		try {
			//lekérjük a c értékét
			c = Integer.parseInt(ConfigManager.getC().getValue("C_value"));
			currentNode.setc(c);
		} catch (NumberFormatException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
    	try {
			//lekérjük a hatvány értékét
			hatvany = Integer.parseInt(ConfigManager.getMCTS().getValue("hatvany"));
			hatvany /=10;
			currentNode.sethatvany(hatvany);
		} catch (InvalidPreferencesFormatException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
	

	/**
	 * @param action az ellenfél cselekvésének az értéke(0-2)
	 * a fában egy szintel lejebb lépés, mikor ellenfél jön
	 * első meghívás flopon az első ellenfél cselekvésénél
	 */
	
	

	/**
	 * @param action 0=fold, 1=check/call, 2=raise 
	 * @param playerID 
	 * @param bet amennyit összesen emel. pl: sb 1, bb 2, utg 4, és emel 4-el akkor ez a szám 8
	 */
	public void stepDownOneAction(int action, int playerseat, double bet ){
		Controller.debugWindow.printMessage("stepDownOneAction");
		
		
		
		/**
		 * beállítjuk a jelenlegi csúcsot
		 */
		if(root.isLeaf())
			currentNode = root;
		/**
		 * létrehozzuk a gyerekeit ha nincsenek neki
		 */
		if(currentNode.isLeaf())
			currentNode.expand(currentNode);
		else
			currentNode.children[action].creatNode(currentNode, action, currentNode.rules.getPlayerID(currentNode.rules.nextplayer(playerseat, action)), bet, currentNode.level);

		
		String tmp3 = "Nodetype=" + currentNode.typeOfNode + ", childrennumber="+ currentNode.childrenNumber+", actualplayer="+ currentNode.rules.actualplayer+", level=" + currentNode.level;
		
		String tmp2 = "lasaction= " + currentNode.rules.lastaction + ", children.lasaction=" + currentNode.children[action].rules.lastaction;
		//Controller.debugWindow.printMessage(tmp2);
		Controller.debugWindow.printMessage(tmp3);
		
		String tmp = "action =" + action;
		//Controller.debugWindow.printMessage(tmp);
		currentNode= currentNode.children[action];
		String tmp4 = "Nodetype=" + currentNode.typeOfNode + ", childrennumber="+ currentNode.childrenNumber+", actualplayer="+ currentNode.rules.actualplayer+", level=" + currentNode.level;
		Controller.debugWindow.printMessage(tmp4);
		
		
			
	}
	
	/**
	 * @param Card a river vagy turn lap
	 * a fában egy szinttel lejjebb lépés, mikor új lap érkezik az asztalon
	 */
	
	public void stepDownOneNewCard(int Card){
		Controller.debugWindow.printMessage("stepDownOneNewCard");
		
		
		
		/**
		 * létrehozzuk a gyerekeit ha nincsenek neki
		 */
		
		if(root.isLeaf())
			currentNode = root;
		
		
		
		if(currentNode.isLeaf()){
			currentNode.expand(currentNode);
			Controller.debugWindow.printMessage("új lapok létrehozva");
		}
		else
			currentNode.children[Card].creatNode(currentNode, Card+100, currentNode.rules.getPlayerID(currentNode.rules.nextplayer(currentNode.rules.actualplayer, Card+100)), 0, currentNode.level);
		
		

		String tmp3 = "Nodetype=" + currentNode.typeOfNode + ", childrennumber="+ currentNode.childrenNumber+", actualplayer="+ currentNode.rules.actualplayer+", level=" + currentNode.level;
		Controller.debugWindow.printMessage(tmp3);
		//currentNode.children[Card].creatNode(currentNode, Card, -1, 0);
		currentNode = currentNode.children[Card];
		

		String tmp4 = "Nodetype=" + currentNode.typeOfNode + ", childrennumber="+ currentNode.childrenNumber+", actualplayer="+ currentNode.rules.actualplayer+", level=" + currentNode.level;
		Controller.debugWindow.printMessage(tmp4);
			
	}
	
	/**
	 * @return a cselekvés melyet az MCTS választott
	 */
	/*public int getDecision(){
		int roundTmp=1;
		//ha currentnode változik akkor ez vátozik??????
		selectionNode = currentNode.parent.children[currentNode.childrenNumber];
		for(int j=0; j<szimulacio; j++){
			while(currentNode.isOver()){
				//if(currentNode.round==4)
					
					if(currentNode.round>roundTmp && currentNode.round!=3)
						currentNode.selectNewCard(currentNode);
					else
					{
						if(currentNode.nextplayer==myID)
							currentNode.selectAction_my(currentNode);
						else
							currentNode.selectAction_other(currentNode);
					}
				roundTmp=currentNode.round;
			}
			double inpot=currentNode.inpot[currentNode.SVMbemenet.playerIDs[myID]];
			double pot=0;
			for(int i=0; i<10;i++)
				pot+=currentNode.inpot[currentNode.SVMbemenet.playerIDs[i]];
			double EV=((winrate()*pot)- inpot)/inpot;
			currentNode.updateStats(EV);
			visited.removeAll(visited);
		}
		
		selectionNode.delete();
		
		
		return (int)(Math.random()*3);
	}*/
	
	
	double winrate(){
		
		double[] HS = new double[10];
		String tmp = "";
		if(currentNode.isAmIWinner()==1)
			return 1;
		if(currentNode.isAmIWinner()==2)
			return 0;
		
		int[][] card = new int[10][2];
		int[] rank= new int[10];
		HandEvaluator HE = new HandEvaluator();
		Hand hand = new Hand();
		hand.addCard(currentNode.rules.flop1);
		hand.addCard(currentNode.rules.flop2);
		hand.addCard(currentNode.rules.flop3);
		hand.addCard(currentNode.rules.turn);
		hand.addCard(currentNode.rules.river);
		
		for(int i=0; i<10; i++){
			HS[i] = DataBase.getHandStrenght(currentNode.SVMbemenet.playerIDs[i]);
			 tmp += " HS[" + i + "]= " + HS[i];
		}
		
		double counter=0;
		for(int j=0; j<100; j++){
			for(int i=0; i<10; i++){
				if(currentNode.rules.playeringame[i]==1)
				card[i] =range(HS[i], i);			
			}
		
			for(int i=0; i<10; i++){
				if(currentNode.rules.playeringame[i]==1)
					rank[i] = HE.rankHand(card[i][0], card[i][1],hand);
			}
			
			rank[currentNode.rules.myseat] = HE.rankHand(currentNode.rules.elsolap, currentNode.rules.masodiklap, hand);
		
			counter+=isWinner(rank);
			
		}
		counter/=100;
		
		
		Controller.debugWindow.printMessage(tmp);
		Controller.debugWindow.printMessage("counter= " + counter);
		return counter;
	}

	public int getDecision(){
		
		
		Controller.debugWindow.printMessage("getDecision");
		
		selectionNode = currentNode;
		
		String tmp6 = "Nodetype=" + selectionNode.typeOfNode + ", childrennumber="+ selectionNode.childrenNumber+", actualplayer="+ selectionNode.rules.actualplayer+", level=" + selectionNode.level;
		Controller.debugWindow.printMessage(tmp6);

		for(int i=0; i< MCTS; i++)
		{
			currentNode = selectionNode;
			String tmp1 = "                                                            MCTS=" + i;
			Controller.debugWindow.printMessage(tmp1);
			while(!currentNode.isLeaf() && i<MCTS){
				visited.add(currentNode);
				if(currentNode.isOver(currentNode)){
					Controller.debugWindow.printMessage("kiválasztásnál már vége");
					backpropagation(currentNode, selectionNode);
					i++;
					currentNode = selectionNode;
				}
					
				else{
					currentNode =currentNode.select(currentNode);
					String tmp2 = "                            selection=" + i;
					Controller.debugWindow.printMessage(tmp2);

				}
			}
			if(i<MCTS){	
				currentNode.expand(currentNode);
				currentNode = currentNode.select(currentNode);
				visited.add(currentNode);
			

			
				simulationNode = currentNode;
			
				for(int j=0; j< szimulacio; j++)
				{
					String tmp2 = "                                                            szimulacio DARAB=" + j;
					Controller.debugWindow.printMessage(tmp2);
					int k=0;
					while(!currentNode.isOver(currentNode)){
						String tmp5 = "                                                            szimulacioszint=" + k;
						Controller.debugWindow.printMessage(tmp5);
						k++;
					
						currentNode = currentNode.simulate(currentNode);
					
					
					}
					backpropagation(currentNode, selectionNode);
					currentNode = simulationNode;
					delete(simulationNode);
					
				}
			}
			
		}
		if(MCTS==0){
			currentNode.expand(currentNode);
		}
		else
			currentNode = selectionNode;
		
		String tmp = "currentNode.type=" + currentNode.typeOfNode + ", level= " + currentNode.level;
		
		
		
		currentNode = currentNode.decision(currentNode);
		

		String tmp4 = "Nodetype=" + currentNode.typeOfNode + ", childrennumber="+ currentNode.childrenNumber+", actualplayer="+ currentNode.rules.actualplayer+", level=" + currentNode.level;
		Controller.debugWindow.printMessage(tmp4);
		
		//Controller.debugWindow.printMessage("----------------------------------------------------------------------------------------------------------------------");
		PrintStream out = System.out;

		String tmp3;
		switch(currentNode.childrenNumber){
		case 0: tmp3 = "fold"; break;
		case 1: tmp3 = "check/call"; break;
		case 2: tmp3 = "bet"; break;
		default: tmp3 = "default fold"; break;
		}
		String tmp2 = "OnlabBot: " +tmp3;
		out.println( tmp2  );
		
		Controller.debugWindow.printMessage(tmp +" " + tmp2);
		
		
		if(currentNode.childrenNumber>2  ){
			
			Controller.debugWindow.printMessage("ide nem kéne bekerülini:MCTS.getDecision ");
			return 0;
		}
		else
			return currentNode.childrenNumber;
		//return  (int)(Math.random()*3);
		
		
	}
	
	public void delete(TreeNode simulateNode){
		simulateNode.children =null;
	}
	
	
	
	public void backpropagation(TreeNode currentNode, TreeNode selectionNode){
		String tmp= "#######################################       backpropagation level=" + currentNode.level;
		//Controller.debugWindow.printMessage(tmp);
		Controller.debugWindow.printMessage("szülő látogások=" +selectionNode.nVisits + ", gyerek0 látogások= " + selectionNode.children[0].nVisits
				+ ", gyerek1 látogások= " + selectionNode.children[1].nVisits+ ", gyerek2 látogások= " + selectionNode.children[2].nVisits);
		double inpot=currentNode.rules.inpot[currentNode.rules.myseat];
		double pot=0;
		for(int i=0; i<10;i++)
			pot+=currentNode.rules.inpot[i];
		
		double EV=(winrate()*pot)/inpot/2;
		if(inpot==0)
			EV=0.5;
		for (TreeNode node : visited){
			node.nVisits++;
			node.totValue += EV;
		}
		visited.removeAll(visited);
	}
	
	public int[] range(double hs, int seat){
		int[] card = new int[2];
		card[0] = 1;
		card[1] = 2;
		if(seat==currentNode.rules.myseat){
			card[0] = currentNode.rules.elsolap;
			card[1] = currentNode.rules.masodiklap;
		}
		return card;
	}
	
	/**
	 * @param rank 10 ellefelél rankja
	 * @return 0= kikaptunk, 0.5= döntetlen 1= nyertünk
	 */
	public double isWinner(int[] rank){
		

		for(int j=0;j<10;j++)
			if(currentNode.rules.playeringame[j]==1)
				if(rank[currentNode.rules.myseat]<rank[j])
					return 0;

		
		for(int i=0;i<10;i++)
			if(currentNode.rules.playeringame[i]==1)
				if(rank[currentNode.rules.myseat]==rank[i] && i!=currentNode.rules.myseat)
					return 0.5;
				
		
		return 1;
	}
	
}